package com.imooc.security.demo.listener;

import com.imooc.security.demo.other.DeferredResultHolder;
import com.imooc.security.demo.other.MockQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * 监听ContextRefreshedEvent事件。contextRefreshedEvent事件是spring容器初始化完成的事件
 * @author JackYang
 * @description:
 * @create: 2020/6/14 13:39
 */
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    
    @Autowired
    private MockQueue mockQueue;
    @Autowired
    private DeferredResultHolder deferredResultHolder;
    
    private Logger logger = LoggerFactory.getLogger(getClass());
    
    /**
     * contextRefreshedEvent 事件是spring容器初始化完成的事件
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        /**
         * 因为这里有while循环，因此单开一个线程专门进行监听，防止while循环阻塞主线程的执行
         */
        new Thread(()->{
            while (true) {
                if (!StringUtils.isEmpty(mockQueue.getCompleteOrder())){
                    String orderNumber=mockQueue.getCompleteOrder();
                    logger.info("监听器，返回订单处理结果："+orderNumber);
                    /*当DeferredResult<String>的setResult()方法被调用时，表示整个异步处理完成了，要往浏览器返回处理结果了。
                    其中setResult()方法中设置的数据即是要返回给浏览器中的数据*/
                    deferredResultHolder.getMap().get(orderNumber).setResult("place oreder success");
                    mockQueue.setCompleteOrder(null);
                }else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}
/**
 * Callable和Deferredresult做的是同样的事情——释放容器线程，在另一个线程上异步运行长时间的任务。不同的是谁管理执行任务的线程。
 * 异步主要表现在，接收请求的servlet可以不用持续等待结果产生，而可以被释放去处理其他事情。当然，在调用者来看的话，其实还是表现在持续等待30秒。这有利于服务端提供更大的并发处理量。
 * 两者的主要差异，主要在DeferredResult需要自己用线程来处理结果setResult，而Callable的话不需要我们来维护一个结果处理线程。
 * 返回Callable意味着Spring MVC将调用在不同的线程中执行定义的任务。Spring将使用TaskExecutor来管理线程。
 * 在长时间运行的任务执行完毕之前就已经从servlet返回了。这并不意味着客户端收到了一个响应。与客户端的通信仍然是开放的等待结果，但接收到的请求的线程已被释放，并可以服务于另一个客户的请求。
 * tomcat默认的处理最大连接数为200,除了最大连接数，还有一个tomcat的最大处理线程数，如果该处设置小了，那么并发也一定会小
 */
